#ifndef UNICELLS_HPP
#define UNICELLS_HPP

#include "structCellsBase.hpp"
#include "eigenConcat.hpp"

namespace hms
{

namespace uniCells_internal
{

using CentroidsCoordType =
	Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<scalar>, RowVectorXs>;

using CentroidsCoordRow =
	Eigen::Transpose<Eigen::Reshaped<
		const Eigen::Replicate<CentroidsCoordType, Dynamic, Dynamic>,
		Dynamic,
		1
	>>;

using CentroidsExpressionType = EigenCustom::ConcatReturnType<
	EigenCustom::Direction::vertical,
	CentroidsCoordRow,
	CentroidsCoordRow
>;

} // namespace uniCells_internal


template<>
class CellsTraits<UniCells>
{
public:
	using MeshType = UniMesh;

	using ConstantArrayXs = const Eigen::CwiseNullaryOp<
		Eigen::internal::scalar_constant_op<scalar>, ArrayXs>;

	using AreasReturnType = ConstantArrayXs;
	using CircumfsReturnType  = ConstantArrayXs;

#ifdef UNIMESH_PRECALC_CENTROIDS
	using CentroidsReturnType = const Matrix2Xs&;
#else
	using CentroidsReturnType = uniCells_internal::CentroidsExpressionType;
#endif
};


class UniCells : public StructCellsBase<UniCells>
{
public:
	using Traits = CellsTraits<UniCells>;
	using AreasReturnType = typename Traits::AreasReturnType;
	using CircumfsReturnType = typename Traits::CircumfsReturnType;
	using CentroidsReturnType = typename Traits::CentroidsReturnType;
private:
	scalar m_area;
	scalar m_circumf;
	Index m_nxg;
	Index m_nyg;
	Index m_outerSize;

	#ifdef UNIMESH_PRECALC_CENTROIDS
	Matrix2Xs m_centroids;
	#endif

public:
	UniCells() = default;
	UniCells( const UniMesh& );

	auto area() const -> scalar;
	auto circumf() const -> scalar;

private:
	auto centroidsImp() const -> CentroidsReturnType;
	auto areasImp    () const -> AreasReturnType;
	auto circumfsImp () const -> CircumfsReturnType;

	void storeData();

	friend CellsBase;
	friend UniMesh;
};

} // namespace hms

#endif